/**
 * 
 */
package org.hotpotmaterial.codegenn2.config;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.hotpotmaterial.codegenn2.common.HmCodeGenConstants;
import org.hotpotmaterial.codegenn2.common.enums.PluginFormPropertiesEnum;
import org.hotpotmaterial.codegenn2.common.enums.PluginLanguageEnum;
import org.hotpotmaterial.codegenn2.common.enums.PluginPropertiesTypeEnum;
import org.hotpotmaterial.codegenn2.config.bean.PluginFormProperties;
import org.hotpotmaterial.codegenn2.config.bean.PluginMapProperties;
import org.hotpotmaterial.codegenn2.config.bean.PluginProperties;
import org.hotpotmaterial.codegenn2.exception.PluginLoadException;
import org.hotpotmaterial.codegenn2.template.CodeGenerateExcutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.google.common.collect.Lists;

import lombok.extern.slf4j.Slf4j;

/**
 * @author Wenxing
 *
 */
@Configuration
@Slf4j
public class HMPluginConfiguration {

	@Autowired
	private ApplicationContext applicationContext;

	@Bean
	public PluginMapProperties pluginProperties() {
		// 日志
		log.info("Loading all plugins.....");
		// 创建bean实例
		PluginMapProperties pluginMapProperties = new PluginMapProperties();
		// 结果bean初始化
		Map<String, PluginProperties> propsMap = new LinkedHashMap<>();
		// 插件属性
		Map<String, Map<String, String>> mapData = new LinkedHashMap<>();
		Map<String, CodeGenerateExcutor> resultMap = applicationContext.getBeansOfType(CodeGenerateExcutor.class);
		resultMap.forEach((key, value) -> {
			if (mapData.containsKey(key)) {
				// 是否包含想同你的bean名称
				throw new PluginLoadException(
						"Plugin with identification [" + key + "] is duplicated, " + "please change the name");
			} else {
				mapData.put(key, value.getProperties());
			}
		});
		// 解析属性map
		mapData.forEach((key, value) -> {
			log.debug("Loading plugin with identification [{}]......", key);
			PluginProperties properties = new PluginProperties();
			// 表单属性临时map
			Map<String, PluginFormProperties> formPropsMap = new LinkedHashMap<>();
			// 寻找名称属性
			String pluginName = value.get(CodeGenerateExcutor.pluginNameKey);
			if (pluginName == null || !pluginName.equals(key)) {
				// 判断bean的名称与插件名称是否一致
				throw new PluginLoadException("Plugin with identification [" + key + "]'s bean name "
						+ "is not matched with the plugin name, please check it");
			}
			properties.setPluginName(pluginName);
			value.remove(CodeGenerateExcutor.pluginNameKey);
			// 普通属性
			value.forEach((keyP, valueP) -> {
				if (HmCodeGenConstants.PLUGIN_LANGUAGE_KEY.equals(keyP)) {
					// 插件语言
					try {
						// 判断插件语言是否支持
						PluginLanguageEnum.valueOf(valueP);
						properties.setPluginLanguage(valueP);
					} catch (Exception e) {
						throw new PluginLoadException("Plugin with identification [" + pluginName + "] use "
								+ "the unsupported language property, please check it");
					}
				} else if (HmCodeGenConstants.PLUGIN_DESCRIPTION_KEY.equals(keyP)) {
					// 插件描述
					properties.setPluginDescription(valueP);
				} else if (HmCodeGenConstants.PLUGIN_TEMPLATE_KEY.equals(keyP)) {
					// 插件描述
					properties.setPluginTemplate(valueP);
				} else if (HmCodeGenConstants.PLUGIN_OUTPUT_KEY.equals(keyP)) {
					// 插件描述
					properties.setPluginOutput(valueP);
				} else if (HmCodeGenConstants.PLUGIN_TAGS_KEY.equals(keyP)) {
					// 插件标签
					String[] tagArr = valueP.split(",");
					properties.setPluginTags(Arrays.asList(tagArr));
				} else if (keyP != null && keyP.startsWith(HmCodeGenConstants.PLUGIN_PROPERTIES_KEY)) {
					// 插件表单属性
					PluginFormProperties formProps;
					// 解析表单属性
					String[] formPropsArr = keyP.split("\\.");
					if (formPropsArr.length != 3) {
						// 判断格式是否有效
						throw new PluginLoadException("Plugin with identification [" + pluginName + "]'s "
								+ "property [" + keyP + "]'s format is invalid, please check it");
					}
					// 寻找之前的表单属性
					formProps = formPropsMap.get(formPropsArr[1]);
					if (null == formProps) {
						// 新建
						formProps = new PluginFormProperties();
					}
					// 设置属性
					formProps.setName(formPropsArr[1]);
					switch (PluginFormPropertiesEnum.valueOf(formPropsArr[2])) {
					case label:
						// 表单标签
						formProps.setLabel(valueP);
						break;
					case pattern:
						// 表单填写规则
						formProps.setPattern(valueP);
						break;
					case defaultValue:
						// 默认值
						formProps.setDefaultValue(valueP);
						break;
					case type:
						try {
							// 判断插件表单属性类型是否支持
							PluginPropertiesTypeEnum.valueOf(valueP);
							formProps.setType(valueP);
						} catch (Exception e) {
							throw new PluginLoadException("Plugin with identification [" + pluginName + "]'s "
									+ "property [" + keyP + "]'s form property type is not supported, "
											+ "please check it");
						}
						break;
					default:
						throw new PluginLoadException("Plugin with identification [" + pluginName + "]'s "
								+ "property [" + keyP + "]'s properties is not supported, please check it");
					}
					// 放入map中
					formPropsMap.put(formPropsArr[1], formProps);
				}
			});
			// 便利表单属性map
			List<PluginFormProperties> formProperties = Lists.newArrayList();
			formPropsMap.forEach((keyF, valueF) -> {
				formProperties.add(valueF);
			});
			properties.setFormProperties(formProperties);
			
			propsMap.put(key, properties);
			log.debug("Plugin with identification [{}] has been loaded......", key);
		});
		
		pluginMapProperties.setProperties(propsMap);
		
		log.info("All " + mapData.size() + " plugins has been loaded.....");

		return pluginMapProperties;
	}

}
